#include "ResourcesManager.hpp"

using namespace boost;

#define FREEIMAGE_LIB
#include "FreeImage.h"

#include "Exception.hpp"

//The Global Resourcesmanager object
ResourcesManager ResMan;

ResourcesManager::ResourcesManager()
{
	FreeImage_Initialise();
}

GLuint ResourcesManager::GetTexture(std::string Filename)
{
	if(Textures.find(Filename)==Textures.end())
		return Textures[Filename]=LoadTexture(Filename);
	else
		return Textures[Filename];
}

StaticModel* ResourcesManager::GetModel(std::string Filename)
{
	if(Models.find(Filename)==Models.end())
		return (Models[Filename]=shared_ptr<StaticModel>(LoadModel(Filename))).get();
	else
		return (Models[Filename]).get();
}


GLuint ResourcesManager::LoadTexture(std::string filename)
{
	//TODO: use a smartpointer for image
	auto Image = FreeImage_Load(FreeImage_GetFileType(filename.c_str()), filename.c_str());

	if(!Image)
	{
		auto ex = Exception() << ex_message("Image could not be loaded with FreeImage") << ex_file(filename);
		throw ex;
	}

	GLuint NewTex;
	glGenTextures(1, &NewTex);
	glBindTexture(GL_TEXTURE_2D, NewTex);

	auto Image32 = FreeImage_ConvertTo32Bits(Image);
	FreeImage_Unload(Image);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, FreeImage_GetWidth(Image32), FreeImage_GetHeight(Image32), 0,
		GL_BGRA, GL_UNSIGNED_BYTE, FreeImage_GetBits(Image32));

	// enable anisotropic filtering
	const GLfloat anisotropy = 8.f;
	const auto GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE; //Todo: Ugh, i don't have the extensions ready. Replace this.
	const auto GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
	GLfloat max_value = 0;
	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_value);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, std::min(max_value, anisotropy));

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glGenerateMipmap(GL_TEXTURE_2D);

	//TODO: use a smartpointer for image
	FreeImage_Unload(Image32);

	return NewTex;
}


StaticModel* ResourcesManager::LoadModel(std::string Filename)
{
	StaticModel* p=new StaticModel();
	p->Load(Filename);
	return p;
}